require 'json'
require 'stringio'

require 'spoule/auth'
require 'spoule/feature'
require 'spoule/icon'
require 'spoule/json'
require 'spoule/method'
require 'spoule/parameter'

# "kind": "discovery#directoryItem",
#   "id": (value),
#   "name": (value),
#   "version": (value),
#   "title": (value),
#   "description": (value),
#   "discoveryLink": (value),
#   "icons": {
#     "x16": (value),
#     "x32": (value)
#   },
#   "documentationLink": (value),
#   "labels": [
#     (value)
#   ],
#   "preferred": (value)

module Spoule
  class Document
    include Spoule::Json

    attr_reader :id, :name, :version
    attr_accessor :base_path, :description, :documentation_link, :protocol, :title

    def initialize(id, name, version)
      @id = id
      @name = name
      @version = version

      @protocol = 'rest'

      @auths = []
      @features = []
      @icons = []
      @labels = []
      @parameters = []
      @methods = []
      @resources = []
      @schemas = []
    end

    def <<(o)
      case o
      when Spoule::Auth
        @auths << o
      when Spoule::Feature
        @features << o
      when Spoule::Icon
        @icons << o
      when Spoule::Method
        @methods << o
      when Spoule::Parameter::Base
        @parameters << o
      when Spoule::Resource
        @resources << o
      when Spoule::Schema
        @schemas << o
      when String
        @labels << o
      else
        raise "Cannot accept objects of type #{o.class}!"
      end
    end

    def to_json(*opts)
      s = StringIO.new
      s << '{'

      s << _format_json_kvp('kind', 'discovery#restDescription', opts)
      s << ',' + _format_json_kvp('id', id, opts)
      s << ',' + _format_json_kvp('name', name, opts)
      s << ',' + _format_json_kvp('version', version, opts)
      s << ',' + _format_json_kvp('title', title, opts)
      s << ',' + _format_json_kvp('description', description, opts)
      s << ',' + _format_json_prefix('icons', opts)
      s << @icons.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
      s << _format_json_suffix
      s << ',' + _format_json_kvp('documentationLink', documentation_link, opts)
      s << ',' + _format_json_array('labels', @labels, opts)
      s << ',' + _format_json_kvp('protocol', protocol, opts)
      s << ',' + _format_json_kvp('basePath', base_path, opts)

      # -- parameters
      if !@parameters.empty?
        s << ',' + _format_json_prefix('parameters', opts)
        s << @parameters.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
        s << _format_json_suffix
      end

      # -- auth
      if !@auths.empty?
        s << ',' + _format_json_prefix('auth', opts)
        s << _format_json_prefix('oauth2', opts)
        s << _format_json_prefix('scopes', opts)
        s << @auths.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
        s << _format_json_suffix
        s << _format_json_suffix
        s << _format_json_suffix
      end

      # -- features
      if !@features.empty?
        s << ',' + _format_json_array('features', @features, opts)
      end

      # -- schemas
      if !@schemas.empty?
        s << ',' + _format_json_prefix('schemas', opts)
        s << @schemas.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
        s << _format_json_suffix
      end

      # -- methods
      if !@methods.empty?
        s << ',' + _format_json_prefix('scopes', opts)
        s << @methods.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
        s << _format_json_suffix
      end

      # -- resources
      if !@resources.empty?
        s << ',' + _format_json_prefix('resources', opts)
        s << @resources.inject([]) {|a,x| a << x.to_json(opts) }.join(',')
        s << _format_json_suffix
      end

      s << '}'
      s.string
    end

  end # class Document
end # module Spoule

